package cn.autumnorange.app.user.consumer.authorization.security.security;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.SerializationUtils;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.code.RandomValueAuthorizationCodeServices;
import org.springframework.util.Assert;

@Slf4j
public class RedisAuthorizationCodeServiceImpl extends RandomValueAuthorizationCodeServices
    implements RedisAuthorizationCodeService {
  private RedisConnectionFactory connectionFactory;

  public RedisAuthorizationCodeServiceImpl(RedisConnectionFactory connectionFactory) {
    Assert.notNull(connectionFactory, "RedisConnectionFactory required");
    this.connectionFactory = connectionFactory;
  }

  @Override
  protected OAuth2Authentication remove(String code) {
    RedisConnection conn = null;

    OAuth2Authentication authentication = null;
    Exception exception = null;
    try {
      conn = getConnection();
      authentication =
          SerializationUtils.deserialize(
              conn.hGet(AUTH_CODE_KEY.getBytes("utf-8"), code.getBytes("utf-8")));

      if (null != authentication) {
        conn.hDel(AUTH_CODE_KEY.getBytes("utf-8"), code.getBytes("utf-8"));
      }
    } catch (Exception e) {
      exception = e;
      log.error("RedisAuthorizationCodeServiceImpl.remove error:" + e.getMessage());
    } finally {
      conn.close();
      if (exception != null) {
        if (exception instanceof RuntimeException) {
          throw (RuntimeException) exception;
        } else {
          throw new RuntimeException(exception);
        }
      }

      return authentication;
    }
  }

  @Override
  protected void store(String code, OAuth2Authentication authentication) {
    Exception exception = null;
    RedisConnection conn = null;
    try {
      conn=getConnection();
      conn.hSet(
          AUTH_CODE_KEY.getBytes("utf-8"),
          code.getBytes("utf-8"),
          SerializationUtils.serialize(authentication));
    } catch (Exception e) {
      exception = e;
      log.error("RedisAuthorizationCodeServiceImpl.store error:" + e.getMessage());

    } finally {
      conn.close();
      if (exception != null) {
        if (exception instanceof RuntimeException) {
          throw (RuntimeException) exception;
        } else {
          throw new RuntimeException(exception);
        }
      }
    }
  }

  private RedisConnection getConnection() {
    return connectionFactory.getConnection();
  }
}
